﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;

namespace TransportAbstractionLibrary.Common.BufferPool
{
    sealed public class BufferManager
    {
        LinkedList<BufferInstance> list;
        volatile int listSize;
        object locker;
        int bufferSize;
        int count;

        public int BufferSize
        {
            get { return bufferSize; }
        }

        BufferInstance[] Array
        {
            get
            {
                lock(locker)
                {
                    LinkedListNode<BufferInstance> item = list.First;
                    BufferInstance[] temp = new BufferInstance[listSize];
                    for (int i = 0; i < listSize; i++)
                    {
                        temp[i] = item.Value;
                        item = item.Next;
                    }
                    return temp;
                }
            }
        }

        public BufferManager(int bufferSize, int count)
        {
            this.bufferSize = bufferSize;
            this.count = count;
            list = new LinkedList<BufferInstance>();
            list.AddFirst(new BufferInstance(bufferSize, count));
            listSize = 1;
            locker = new object();
        }

        public SocketEventArgs CheckOut()
        {
            SocketEventArgs value = null;
            //use Array then we are can loop that and we dont have to use a lock Array will do this for us.
            BufferInstance[] array = Array;
            for (int i = 0; i < array.Length; i++)
            {
                value = array[i].CheckOut();
                if (value != null)
                {
                    break;
                }
            }
            while (value == null)
            {
                value = AddNewInstance();
            }
            return value;
        }

        public void CheckIn(SocketEventArgs args)
        {
            BufferInstance[] array = Array;
            for (int i = 0; i < array.Length; i++)
            {
                if (array[i].CheckIn(args))
                {
                    return;
                }
            }
            //todo throw some thing else
            throw new InvalidOperationException("The socket args dosent seem to be right!");
        }

        private SocketEventArgs AddNewInstance()
        {
            BufferInstance instance = new BufferInstance(bufferSize, count);
            SocketEventArgs value = instance.CheckOut();
            lock(locker)
            {
                list.AddFirst(instance);
                listSize += 1;
            }
            return value;
        }
    }
}
